package org.statewalker.core.server;

import java.util.Map;
import java.util.concurrent.CyclicBarrier;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.statewalker.core.Core;
import org.statewalker.core.ErrorEvent;
import org.statewalker.core.IEvent;
import org.statewalker.core.IProcessContext;
import org.statewalker.core.IState.ICallback;

public class ServerContext implements IProcessContext {

    private static Logger fLogger = Logger
        .getLogger(ServerContext.class.getName());

    private Accessor fAccessor = new Accessor();

    private Core fCore;

    /**
     * @param siteConfig
     */
    public ServerContext(Core core) {
        fCore = core;
    }

    public ServerContext(ServerContext context) {
        fCore = context.fCore;
        setValues(context.getValues());
    }

    public <T> T getAccessor(Class<T> type) {
        return fAccessor.getAccessor(type);
    }

    public Core getCore() {
        return fCore;
    }

    public Map<String, Object> getValues() {
        return fAccessor.getMap();
    }

    private IEvent handleError(Throwable e) {
        fLogger.log(Level.SEVERE, e.getMessage());
        ErrorEvent event = new ErrorEvent(e);
        return event;
    }

    public IEvent runProcess(String processName) {
        final IEvent[] result = { null };
        try {
            boolean ok = false;
            final CyclicBarrier barrier = new CyclicBarrier(2);
            try {
                startProcess(processName, new ICallback() {
                    public void finish(IEvent event) {
                        try {
                            result[0] = event;
                            barrier.await();
                        } catch (Throwable e) {
                            result[0] = handleError(e);
                        }
                    }
                });
                ok = true;
            } finally {
                if (ok) {
                    barrier.await();
                }
            }
        } catch (Throwable t) {
            result[0] = handleError(t);
        }
        return result[0];
    }

    public void setValues(Map<String, Object> values) {
        fAccessor.setMap(values);
    }

    public void startProcess(String processName, ICallback callback) {
        fCore.startProcess(processName, this, callback);
    }
}
